package com.jctrip.hotel.common.threadpool;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import lombok.extern.slf4j.Slf4j;

/**
 * xxl-job线程池
 */
@Slf4j
public class XxlJobThreadPool {

    private static final Integer CORE_POOL_SIZE = 4;

    private static final Integer MAXIMUM_POOL_SIZE = 9;

    private static final Long KEEP_ALIVE_TIME = 0L;

    private static final Integer QUEUE_CAPACITY_SIZE = 1024;

    private final ExecutorService pool;

    private final String xxlJobName;

    public XxlJobThreadPool(String xxlJobName) {
        this.xxlJobName = xxlJobName;
        this.pool = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(QUEUE_CAPACITY_SIZE),
                new ThreadFactoryBuilder().setNameFormat(xxlJobName + "-pool-%d").build(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

    private <T extends Runnable> Future<?> submit(T command) {
        try {
            return pool.submit(command);
        } catch (Exception e) {
            log.error(xxlJobName + " pool execute error", e);
            return null;
        }
    }

    public <T extends Runnable> void execute(Supplier<T> creator) {
        // 默认4线程
        execute(creator, 4);
    }

    public <T extends Runnable> void execute(Supplier<T> creator, int threads) {
        Map<Integer, Future<?>> futureMap = new HashMap<>();
        for (int i = 0; i < 4; i++) {
            try {
                T command = creator.get();
                Future<?> future = this.submit(command);
                if (null != future) {
                    futureMap.put(i, future);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        for (int i = 0; i < 4; i++) {
            try {
                Future<?> future = futureMap.get(i);
                if (null != future) {
                    future.get();
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }
}
